home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_02_04 / 2n04028a < prev    next >
Text File  |  1991-02-23  |  10KB  |  383 lines

  1. { Listing 3  -- floppy.c}
  2.  
  3.  
  4. **  This file contains the various functions used to 
  5. **  control the Floppy Disk Controller (FDC).
  6. */
  7. #include    <stdio.h>
  8. #include    <dos.h>
  9. #include    "floppy.h"
  10. #include    "delay.h"
  11.  
  12. /* Global data */
  13. byte Results[7];
  14.  
  15. /* Command Strings */
  16. static byte SpecifyCmd[] = { FdcCmdSpecify, 0, 0 };
  17. static byte SenseDriveCmd[] = { FdcCmdSenseDrive, 0 };
  18. static byte SenseIntCmd[] = { FdcCmdSenseInt };
  19. static byte RecalCmd[] = { FdcCmdRecalibrate, 0 };
  20. static byte SeekCmd[] = { FdcCmdSeek, 0, 0 };
  21. static byte ReadCmd[] = { FdcCmdRead, 0, 0, 0, 0, 2, 9, 
  22.                           0x2a, 0xff };
  23. static byte ReadTrackCmd[] = { FdcCmdReadTrack, 0, 0, 0, 
  24.                                0, 2, 9, 0x2a, 0xff };
  25. static byte WriteCmd[] = { FdcCmdWrite, 0, 0, 0, 0, 2, 9, 
  26.                            0x2a, 0xff };
  27. static byte FormatTrackCmd[] = { FdcCmdFormatTrack, 0, 2, 
  28.                                  9, 0x50, 0xff };
  29.  
  30. /* Local data */
  31. static byte StepRateTime = 0x0c,
  32.             HeadUnloadTime = 0x0f,
  33.             HeadLoadTime = 0x02;
  34. static byte Drive;
  35. static byte Cylinder = 0, Head = 0;
  36. static unsigned BytesPerSector = 512;
  37. static byte SectorsPerTrack = 9;
  38. volatile static byte Interrupt = 0;
  39. static void interrupt (*oldFdcInt)(void);
  40.  
  41. #define TRUE    1
  42. #define FALSE   0
  43.  
  44. /* Process FDC Interrupt request */
  45. void interrupt fdcInterrupt(void)
  46. {
  47.     Interrupt = TRUE;
  48.     (*oldFdcInt)();
  49. }
  50.  
  51. /* Set local drive parameters value */
  52. void fdcSetDriveParms(byte srt, byte hut, byte hlt)
  53. {
  54.     StepRateTime = srt;
  55.     HeadUnloadTime = hut;
  56.     HeadLoadTime = hlt;
  57.  
  58.     SpecifyCmd[1] = (StepRateTime << 4) | HeadUnloadTime;
  59.     SpecifyCmd[2] = HeadLoadTime << 1;
  60.  
  61.     /* Setup interrupt hook, if not already set */
  62.     if (oldFdcInt == NULL)
  63.     {
  64.         oldFdcInt = getvect(0x0e);
  65.         setvect(0x0e, fdcInterrupt);
  66.     }
  67. }
  68.  
  69. /* Reset FDC interupt vector */
  70. void fdcResetParms(void)
  71. {
  72.     if (oldFdcInt != NULL)
  73.     {
  74.         setvect(0x0e, oldFdcInt);
  75.         oldFdcInt = NULL;
  76.     }
  77. }
  78.  
  79. /* Reset FDC and drives */
  80. void fdcReset(void)
  81. {
  82.     /*
  83.     ** Turn on the FDC's reset mode, disable DMA 
  84.     ** transfers, and turn off all drive motors.
  85.     */
  86.     fdcSetDOR(FdcDorReset | FdcDorDmaDisable);
  87.  
  88.     fdcDelay();
  89.  
  90.     /* turn off reset mode and enable DMA transfers */
  91.     fdcSetDOR(FdcDorClearReset | FdcDorDmaEnable);
  92.  
  93.     /* Get the drive status  */
  94.     fdcSenseDrive();
  95.  
  96.     /* Remind the controller what parameters we are using */
  97.     fdcSpecify();
  98. }
  99.  
  100. /* Select, and turn on, the specified drive */
  101. void fdcSelectDrive(byte drive)
  102. {
  103.     drive &= 0x03;    /* Limit drive numbers from 0 to 3 */
  104.     Drive = drive;
  105.  
  106.     /* Set Command strings based on drive number */
  107.     SenseDriveCmd[1] = (SenseDriveCmd[1] & ~0x03) | Drive;
  108.     RecalCmd[1] = Drive;
  109.  
  110.     fdcSetDOR((FdcDorDriveOn << drive) | FdcDorDmaEnable |
  111.         FdcDorClearReset | drive);
  112. }
  113.  
  114. /* Specify drive parameters */
  115. int fdcSpecify(void)
  116. {
  117.     fdcSendCmd(SpecifyCmd, sizeof(SpecifyCmd));
  118.     return fdcResultPhase(FALSE, 0);
  119. }
  120.  
  121. /* Sense Drive Status */
  122. unsigned fdcSenseDrive(void)
  123. {
  124.     fdcSendCmd(SenseDriveCmd, sizeof(SenseDriveCmd));
  125.     return fdcResultPhase(TRUE, 1);
  126. }
  127.  
  128. /* Get information concerning the last drive interrupt */
  129. unsigned fdcSenseInterrupt(void)
  130. {
  131.     fdcSendCmd(SenseIntCmd, sizeof(SenseIntCmd));
  132.     return fdcResultPhase(TRUE, 2);
  133. }
  134.  
  135. /* Recalibrate the drive */
  136. unsigned fdcRecalibrate(void)
  137. {
  138.     Cylinder = Head = 0;
  139.  
  140.     fdcSendCmd(RecalCmd, sizeof(RecalCmd));
  141.  
  142.     fdcWaitForInt();
  143.     return fdcSenseInterrupt();
  144. }
  145.  
  146. /* Seek the drive heads to the specified cylinder */
  147. unsigned fdcSeek(int head, int cylinder)
  148. {
  149.     Cylinder = cylinder;
  150.     Head = head;
  151.  
  152.     SeekCmd[1] = (head << 2) | Drive;
  153.     SeekCmd[2] = cylinder;
  154.  
  155.     fdcSendCmd(SeekCmd, sizeof(SeekCmd));
  156.  
  157.     fdcWaitForInt();
  158.     return fdcSenseInterrupt();
  159. }
  160.  
  161. /*
  162. ** Read a number of sectors from the current track into 
  163. ** the read buffer passed by the caller.
  164. */
  165. unsigned fdcReadSectors(int sector, unsigned nsect, 
  166.                         void* buffer)
  167. {
  168.     unsigned byteCount = nsect * BytesPerSector;
  169.  
  170.     /* Test for buffer fitting within a single DMA page */
  171.     if (!dmaPageTest(buffer, byteCount))
  172.         return -5;
  173.  
  174.     /* Setup DMA Controller */
  175.     dmaSetup(DmaCmdRead, byteCount, buffer);
  176.  
  177.     ReadCmd[1] = (Head << 2) | Drive;
  178.     ReadCmd[2] = Cylinder;
  179.     ReadCmd[3] = Head;
  180.     ReadCmd[4] = sector;
  181.  
  182.     fdcSendCmd(ReadCmd, sizeof(ReadCmd));
  183.     return fdcResultPhase(FALSE, 7);
  184. }
  185.  
  186. unsigned fdcReadTrack(void* buffer)
  187. {
  188.     /* Test for buffer fitting within DMA boundries */
  189.     if (!dmaPageTest(buffer, SectorsPerTrack * 
  190.         BytesPerSector))
  191.           return -5;
  192.  
  193.     /* Setup DMA Controller */
  194.     if (!dmaSetup(DmaCmdRead, SectorsPerTrack * 
  195.         BytesPerSector, buffer))
  196.           return -5;
  197.  
  198.     ReadTrackCmd[1] = (Head << 2) | Drive;
  199.     ReadTrackCmd[2] = Cylinder;
  200.     ReadTrackCmd[3] = Head;
  201.  
  202.     fdcSendCmd(ReadTrackCmd, sizeof(ReadTrackCmd));
  203.     return fdcResultPhase(FALSE, 7);
  204. }
  205.  
  206. /*
  207. ** Write a number of sectors from the current track from 
  208. ** the read buffer passed by the caller.
  209. */
  210. unsigned fdcWriteSectors(int sector, unsigned nsect, 
  211.                          void* buffer)
  212. {
  213.     unsigned byteCount = nsect * BytesPerSector;
  214.  
  215.     /* Test for buffer fitting within a single DMA page */
  216.     if (!dmaPageTest(buffer, byteCount))
  217.         return -5;
  218.  
  219.     /* Setup DMA Controller */
  220.     dmaSetup(DmaCmdWrite, byteCount, buffer);
  221.  
  222.     WriteCmd[1] = (Head << 2) | Drive;
  223.     WriteCmd[2] = Cylinder;
  224.     WriteCmd[3] = Head;
  225.     WriteCmd[4] = sector;
  226.  
  227.     fdcSendCmd(WriteCmd, sizeof(WriteCmd));
  228.     return fdcResultPhase(FALSE, 7);
  229. }
  230.  
  231. /* Format the current track */
  232. unsigned fdcFormatTrack(void* buffer)
  233. {
  234.     /* Test for buffer fitting within DMA boundries */
  235.     if (!dmaPageTest(buffer, SectorsPerTrack * 4))
  236.         return -5;
  237.  
  238.     /* Setup DMA Controller */
  239.     if (!dmaSetup(DmaCmdWrite, SectorsPerTrack * 4, buffer))
  240.         return -5;
  241.  
  242.     FormatTrackCmd[1] = (Head << 2) | Drive;
  243.     FormatTrackCmd[2] = Head;
  244.  
  245.     fdcSendCmd(FormatTrackCmd, sizeof(FormatTrackCmd));
  246.     return fdcResultPhase(FALSE, 7);
  247. }
  248.  
  249. int fdcSendCmd(byte* cmd, unsigned cmdlen)
  250. {
  251.     int rqmTimeout, i;
  252.  
  253.     /* Send the command to the FDC */
  254.     for (i = 0 ; i < cmdlen ; ++i)
  255.     {
  256.         fdcDelay();
  257.  
  258.         /* Wait for the RQM flag */
  259.         rqmTimeout = 0;
  260.         while ((fdcGetStatus() & FdcMsrRequest) != 
  261.                 FdcMsrRequest)
  262.         {
  263.             if (++rqmTimeout > 1000)
  264.                 return -1;
  265.         }
  266.  
  267.         /* Check that the FDC is ready for input */
  268.         if ((fdcGetStatus() & FdcMsrDirection) != 0)
  269.             return -2;
  270.  
  271.         fdcWriteCmd(*cmd);
  272.         ++cmd;
  273.     }
  274.  
  275.     return 0;
  276. }
  277.  
  278. /* Wait for an interrupt */
  279. void fdcWaitForInt(void)
  280. {
  281.     while (!Interrupt)
  282.         ;
  283.  
  284.     Interrupt = FALSE;
  285. }
  286.  
  287. /* Wait for result data */
  288. int fdcResultPhase(int immediate, int nres)
  289. {
  290.     /* wait for interrupt if not immediate result phase */
  291.     if (!immediate)
  292.         fdcWaitForInt();
  293.  
  294.     /* Turn off the interrupt flag */
  295.     Interrupt = FALSE;
  296.  
  297.     /* Input results from the FDC */
  298.     if (immediate || (fdcGetStatus() & FdcMsrFdcBusy) != 0)
  299.     {
  300.         /* operation is completed, get FDC result bytes */
  301.         int i, rqmTimeout;
  302.  
  303.         for (i = 0 ; i < nres ; ++i)
  304.         {
  305.             fdcDelay();
  306.  
  307.             /* Wait for the RQM flag */
  308.             rqmTimeout = 0;
  309.             while ((fdcGetStatus() & FdcMsrRequest) != 
  310.                     FdcMsrRequest)
  311.             {
  312.                 if (++rqmTimeout > 1000)
  313.                     return -1;
  314.             }
  315.     
  316.             /* Check that the FDC is ready for input */
  317.             if ((fdcGetStatus() & FdcMsrDirection) == 0)
  318.                 return -2;
  319.  
  320.             Results[i] = fdcGetResult();    
  321.         }
  322.  
  323.         /* Make sure that FDC has completed sending data */
  324.